package primeraEntregaMain

import java.util.Date
import javax.persistence.GeneratedValue
import javax.persistence.Id
import javax.persistence.GenerationType
import javax.persistence.Entity
import scala.collection.mutable.Buffer
import aerolineasYVuelos.Asiento
import javax.persistence.OneToMany
import scala.collection.JavaConverters._
import java.util.ArrayList
import org.hibernate.annotations.Fetch
import org.hibernate.annotations.FetchMode
import aerolineasYVuelos.Tramo
import aerolineasYVuelos.Vuelo
import aerolineasYVuelos.Aerolinea
import scala.collection.mutable.ArrayBuffer
import excepciones.AsientoReservadoException
import servicios.ServicioReserva
import javax.persistence.CascadeType
import servicios.ServicioTramo
import servicios.ServicioAerolinea
import busquedas.Busqueda
import aerolineasYVuelosDaos.UsuarioDAO
import servicios.ServicioUsuario
import org.neo4j.graphdb.Node
import graphNeo4j.Graph
import org.neo4j.graphdb.Relationship
import org.neo4j.graphdb
import graphNeo4j.UserNodeService

@Entity
class Usuario {

  @Id
  @GeneratedValue(strategy = GenerationType.AUTO)
  var id: Int = _
  def getId = id
  def setId(i: Int) { id = i }
  
  var nombre: String = _
  def getNombre = nombre
  def setNombre(s: String) { nombre = s }
  
  var apellido: String = _
  def getApellido = apellido
  def setApellido(s: String) { apellido = s }
  
  var nombreDeUsuario: String = _
  def getNombreDeUsuario = nombreDeUsuario
  def setNombreDeUsuario(s: String) { nombreDeUsuario = s }
  
  var email: String = _
  def getEmail = email
  def setEmail(s: String) { email = s }
  
  var fechaDeNacimiento: Date = _
  def getFechaDeNacimiento = fechaDeNacimiento
  def setFechaDeNacimiento(date: Date) { fechaDeNacimiento = date}
  
  var password: String = _
  def getPassword = password
  def setPassword(s: String) { password = s }
  
  var validado: Boolean = _
  def getValidado = validado
  def setValidado(bool: Boolean) { validado = bool }
  
  @OneToMany(mappedBy = "usuario", cascade = Array(CascadeType.ALL))
  @Fetch(value = FetchMode.SUBSELECT)
  var asientos: java.util.List[Asiento] = new ArrayList[Asiento]
  def getAsientos = asientos
  def setAsientos(as :java.util.List[Asiento]) { asientos = as }
  
  @OneToMany(cascade = Array(CascadeType.ALL))
  @Fetch(value = FetchMode.SUBSELECT)
  var busquedas: java.util.List[Busqueda] = new ArrayList[Busqueda]
  def getBusquedas = busquedas
  def setBusquedas(bs: java.util.List[Busqueda]) { busquedas = bs }
  
  def inicializarUsuario(nombre: String, apellido: String, nombreDeUsuario: String,
		  			email: String, fechaDeNacimiento: Date, password: String, validado: Boolean) {
    
	  	  setNombre(nombre)
		  setApellido(apellido)
		  setNombreDeUsuario(nombreDeUsuario)
		  setEmail(email)
		  setFechaDeNacimiento(fechaDeNacimiento)
		  setPassword(password)
		  setValidado(validado)
  }
  
  def getAsientosScala = getAsientos.asScala.toBuffer[Asiento]
  
  def cambiarPassword (nuevoPass :String) { password =  nuevoPass }
  
  def validarUsuario = { validado = true }
  
  def agregarAsiento(asiento :Asiento) { getAsientosScala += asiento }
  
  /**
   * Si en la lista de asientos, hay por lo menos un asiento reservado, tira una
   * excepcion y no reserva ninguno, de lo contrario reserva todos
   */
  def validaYReserva(asientos: Buffer[Asiento]) {
	  	if(asientos.exists(_.estaReservado)) {
		  throw new AsientoReservadoException
		} else {
		  ServicioReserva.reservarAsiento(asientos, this)
		}
  }
  
  /**
   * Solicita a la empresa reservar un asiento determinado 
   * que se guardara el usuario una vez que lo reserve en su lista
   */
  def reservarAsiento(miAsiento :Asiento){
    var unAsiento = new ArrayBuffer[Asiento]
    unAsiento += miAsiento

    validaYReserva(unAsiento)
    
  }
  
  /**
   * Reserva un conjunto de asientos para el usuario 
   */
  def reservarConjuntoDeAsientos(misAsientos : Buffer [Asiento]) ={
	  validaYReserva(misAsientos)
  }

  /**
   * Devuelve una lista de asientos que estan en estado NO reservado
   */
  def consultarAsientosLibres (unTramo :Tramo) :Buffer[Asiento] = {
	  ServicioTramo.consultarAsientosLibres(unTramo)
  }
  
  /**
   * Delega a la busqueda el crear un filtro por aerolinea
   */
  def agregarFiltroPorAerolinea(busqueda: Busqueda, unaAerolinea: Aerolinea) {
	  busqueda.crearFiltroPorAerolinea(unaAerolinea)
	  ServicioUsuario.agregarUsuario(this)
  }
  
  /**
   * Delega a la busqueda el crear un filtro por origen y destino
   */
  def agregarFiltroPorOrigenYDestino(busqueda: Busqueda, origen: String, destino: String) {
   	  busqueda.crearFiltroPorOrigenYDestino(origen, destino)
   	  ServicioUsuario.agregarUsuario(this)
  }
  
  /**
   * Delega a la busqueda el crear un filtro por hora de salida
   */
  def agregarFiltroPorHoraSalida(busqueda: Busqueda, horaSalida: Date) {
	  busqueda.crearFiltroPorHoraSalida(horaSalida)
	  ServicioUsuario.agregarUsuario(this)
  }
  
  /**
   * Delega a la busqueda el crear un filtro por hora de llegada
   */
  def agregarFiltroPorHoraLlegada(busqueda: Busqueda, horaLlegada: Date) {
	  busqueda.crearFiltroPorHoraLlegada(horaLlegada)
	  ServicioUsuario.agregarUsuario(this)
  }
  
  /**
   * Delega a la busqueda el ordenamiento por menos escalas
   */
  def ordenarPorMenosEscalas(busqueda: Busqueda) {
	  busqueda.crearOrdenamientoPorMenosEscalas
  }
  
  /**
   * Delega a la busqueda el ordenamiento por duracion
   */
  def ordenarPorDuracion(busqueda: Busqueda) {
	  busqueda.crearOrdenamientoPorDuracion
  }
  
  /**
   * Delega a la busqueda el ordenamiento por precio
   */
  def ordenarPorPrecio(busqueda: Busqueda) {
	  busqueda.crearOrdenamientoPorPrecio
  }
  	
  /**
   * Delega a la busqueda el ejecutar todos sus filtros que tiene guardados
   */
  def ejecutarBusqueda(busqueda: Busqueda): Buffer[Vuelo] = {
	busqueda.ejecutarBusqueda
  }
  
}